import { Document, Tag, Task, sequelize, Sequelize } from '../models'

import * as $task from './task'

/**
 * 创建作业
 * @param  {Int}  userId 用户信息
 * @param  {page}  type   作业类型
 * @param  {String}  name   名称
 * @param  {Json}  data   结构数据
 * @param  {Json}  layout 布局数据
 * @param  {Json}  meta   其它数据
 * @param  {Datetime}  endAt  截至时间
 * @return {Promise}        [description]
 */
export const create = async (
  userId,
  { id, type, name, data, layout, meta, endAt = null }
) => {
  let document = null
  endAt = endAt || null
  if (id) {
    document = await Document.findById(id)
    document.name = name
    document.data = data
    document.layout = layout
    document.meta = meta
    document.endAt = endAt
    await document.save()
    return document
  }
  document = await Document.create({
    userId,
    type,
    name,
    data,
    layout,
    meta,
    endAt
  })
  return document
}

export const publish = async (
  { userId, documentId, groupIds, endAt = '', prePublishAt = '' }
) => {
  let document = await Document.findById(documentId)
  let tasks = []
  for (let i = 0; i < groupIds.length; i++) {
    let groupId = groupIds[i]
    let task = await $task.findOrCreate({documentId, userId, groupId, endAt, prePublishAt})
    tasks.push(task)
  }
  document.isPublished = 1
  await document.save()
  return tasks
}

/**
 * 布置作业
 * @param  {Int}  userId             登录者id
 * @param  {String}  [type='page']      文档类型
 * @param  {String}  name               文档名称
 * @param  {JSON}  blocks             文档内容
 * @param  {[Int]}  groupIds           所布置到的群组ID
 * @param  {String}  [endAt='']         结束时间
 * @param  {String}  [prePublishAt=''}] 预布置时间
 * @return {[Task]}                    任务列表数据
 */
export const arrange = async ({
  userId,
  type = 'page',
  name,
  blocks,
  groupIds,
  layout = null,
  meta = null,
  endAt = null,
  prePublishAt = null
}) => {
  return sequelize.transaction({
    isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE
  }, async t => {
    name = name.trim()
    if (!name) throw new Error('名称不能为空')
    if (!blocks.length) throw new Error('内容不能为空')
    endAt = endAt || null
    prePublishAt = prePublishAt || null
    let isPublished = prePublishAt ? 0 : 1
    // 创建文档
    let documents = []
    groupIds.forEach(n => {
      documents.push({
        userId,
        type,
        name,
        data: {blocks},
        endAt,
        layout,
        meta,
        isPublished
      })
    })
    documents = await Document.bulkCreate(documents, {
      transaction: t
    })

    // 根据文档和组创建任务
    let dids = documents.map(n => n.id)
    let tasks = []
    for (let i = 0; i < groupIds.length; i++) {
      let groupId = groupIds[i]
      tasks.push({
        documentId: dids[i],
        versionId: dids[i],
        ownerId: userId,
        userId,
        groupId,
        isPublished,
        expireAt: endAt,
        prePublishAt
      })
    }
    tasks = await Task.bulkCreate(tasks, {
      transaction: t
    })

    // 创建进程
    for (let i = 0; i < tasks.length; i++) {
      let task = tasks[i]
      await $task.bulkCreateProgress({taskId: task.id, transaction: t})
    }

    // 发布作业
    if (isPublished) {
      for (let i = 0; i < tasks.length; i++) {
        let task = tasks[i]
        await $task.publish(task.id, t)
      }
    }

    return tasks
  })
}

/**
 * Update an existing document
 *
 * @param {int} documentId
 * @param {int} userId
 * @param {object} data
 * @return {object} Document
 */
export const update = async (
  documentId,
  userId,
  { type, name, data, layout, meta }
) => {
  let document = await Document.findById(documentId)
  if (document == null) {
    throw new Error(`${ERRORS.DBERR.ERR_RECORD_NOT_FOUND}`)
  }
  if (userId && document.userId != userId) {
    throw new Error(`${ERRORS.DBERR.ERR_UNAUTHORIZED_OPERATION}`)
  }
  document.type = type
  document.name = name
  document.data = data
  document.layout = layout
  document.meta = meta
  return await document.save()
}

/**
 * Remove an existing document
 * @param {int} documentId
 * @param {int} userId
 * @return {object} Document
 */
export const remove = async (documentId, userId) => {
  let document = await Document.findById(documentId)
  if (document == null) {
    throw new Error(`${ERRORS.DBERR.ERR_RECORD_NOT_FOUND}`)
  }
  if (userId && document.userId != userId) {
    throw new Error(`${ERRORS.DBERR.ERR_UNAUTHORIZED_OPERATION}`)
  }
  return await document.destroy()
}

/**
 * List all documents the user has
 * Order by updateAt
 * @param {int} userId
 * @return {array} Documents
 */
export const findAllUserDocuments = async (
  userId,
  pageIndex = 0,
  pageSize = 20
) => {
  const result = await Document.findAndCountAll({
    where: {
      userId,
      documentId: null
    },
    offset: pageIndex * pageSize,
    limit: pageSize,
    order: [['updatedAt', 'DESC']]
  })
  return result
}

/**
 * List all documents the user has
 * Order by updateAt
 * @param {int} tagId 标签ID
 * @param {int} pageSize 每页数量
 * @param {String} cursor 指针
 * @return {array} Documents
 */
export const findDocumentsByTagId = async ({
  tagId,
  cursor: { limit = 10, before, after }
}) => {
  let query = {
    where: {
      documentId: null
    },
    limit,
    order: [['updatedAt', 'DESC']]
  }
  if (before) {
    query.before = before
  }
  if (after) {
    query.after = after
  }
  if (tagId) {
    query.include = [
      {
        model: Tag,
        as: 'TagDocuments',
        attributes: ['id'],
        where: { id: tagId }
      }
    ]
  }
  const result = await Document.paginate(query)
  return result
}
